package com.tang.netty.nio;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

/**
 * 适配器
 */
@Slf4j
public abstract class ChannelAdapter extends Thread {

    private Selector selector;
    private ChannelHandler channelHandler;
    private Charset charset;

    public ChannelAdapter(Selector selector, Charset charset) {
        this.selector = selector;
        this.charset = charset;
    }

    @Override
    public void run() {
        while (true) {
            try {
                // 获取可用channel
                int readyChannel = selector.select(1000);
                if (readyChannel == 0) continue;
                // 获取可用channel的集合
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    iterator.remove();
                    // 根据就绪状态，调用对应方法处理业务逻辑
                    handleinput(selectionKey);
                }
            } catch (IOException e) {
                log.error("{}", e.getMessage());
            }
        }
    }

    private void handleinput(SelectionKey selectionKey) throws IOException {
        if (!selectionKey.isValid()) return;

        Class<?> superclass = selectionKey.channel().getClass().getSuperclass();

        // 客户端请求
        if (superclass == SocketChannel.class) {
            SocketChannel channel = (SocketChannel) selectionKey.channel();
            if (selectionKey.isConnectable()) {
                if (channel.finishConnect()) {
                    channelHandler = new ChannelHandler(channel, charset);
                    channelActive(channelHandler);
                    channel.register(selector, SelectionKey.OP_READ);
                } else {
                    System.exit(1);
                }
            }
        }

        //服务端ServerSocketChannel
        if (superclass == ServerSocketChannel.class) {
            // 如果是链接事件：那就是用channelActive
            if (selectionKey.isAcceptable()) {
                // 1.创建socketChannel
                ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
                SocketChannel socketChannel = serverSocketChannel.accept();
                // 2.将socket设置为非阻塞工作模式
                socketChannel.configureBlocking(false);
                socketChannel.register(selector, SelectionKey.OP_READ);
                channelHandler = new ChannelHandler(socketChannel, charset);
                channelActive(channelHandler);
            }
        }

        // 如果是读写事件，那就是使用读写Handler处理
        if (selectionKey.isReadable()) {
            // 1.从selectKey中获取已经就绪的channel
            SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
            // 2.创建buffer
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            // 3.循环读取客户端请求信息
            int read = socketChannel.read(byteBuffer);
            if (read > 0) {
                byteBuffer.flip();
                byte[] bytes = new byte[byteBuffer.remaining()];
                byteBuffer.get(bytes);
                channelRead(channelHandler, new String(bytes, charset));
            } else if (read < 0) {
                selectionKey.cancel();
                socketChannel.close();
            }
        }

    }


    // 链接通知抽象类
    public abstract void channelActive(ChannelHandler channelHandler);

    // 读取消息抽象类
    public abstract void channelRead(ChannelHandler channelHandler, Object msg);

}
